/*
 * Copyright 2010 Assert Developments
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.google.inject.factory;

import com.google.inject.binder.ClassBinder;

/**
 * An abstract factory that implements the creation of the class binder and separates the lookup of the class with
 * instantiation of the class.
 *
 * @author Stefan Bangels
 */
abstract class AbstractFactory<T> implements Factory<T> {

    /**
     * Create an instance of the class mapped to the specified identifier.
     * Looks up the class linked to the identification using the getBinding() method and instantiates the class using
     * the getInstance() method.
     *
     * @param identifier the identifier
     * @return an instance of the class mapped to the specified identifier
     */
    @Override
    public final T create(String identifier) {
        Class<? extends T> clazz = getBinding(identifier);
        if (clazz != null) {
            return getInstance(clazz);
        }
        return null;
    }

    /**
     * Create a class binder that maps a class to the specified identifier.
     *
     * @param identifier the identifier
     * @return a class binder, that maps a class to the specified identifier
     * @see com.google.inject.binder.ClassBinder
     */
    @Override
    public final ClassBinder<T> map(final String identifier) {
        return new ClassBinder<T>() {
            public void to(Class<? extends T> clazz) {
                bind(identifier, clazz);
            }
        };
    }

    /**
     * Looks up the class for the specified identification.
     *
     * @param identifier the identifier
     * @return the class, or null when it's unbound
     */
    abstract Class<? extends T> getBinding(String identifier);

    /**
     * Binds the identifier to the specified class.
     *
     * @param identifier the identifier
     * @param clazz      the class
     */
    abstract void bind(String identifier, Class<? extends T> clazz);

    /**
     * Get an instance of the specified class.
     *
     * @param clazz the class
     * @return an instance of the specified class
     */
    abstract T getInstance(Class<? extends T> clazz);

}